package com.nc.delivery_project.server.service;

import com.nc.delivery_project.server.dao.AbstractDao;
import com.nc.delivery_project.server.db_util.ConnectionManager;
import com.nc.delivery_project.server.util.CRUD;

import java.sql.Connection;
import java.sql.SQLException;

/**
 * Created by miroshnik on 1/26/2015.
 * 
 * BaseService has the main dao what will be used by the concrete service.
 * It manages the connection with database.
 */
public abstract class BaseService<T> implements CRUD<T> {
    
    protected AbstractDao<T> dao;
    
    private Connection connection;
    
    private boolean isAutoCloseConnection;

    public BaseService(AbstractDao<T> dao, Connection connection, boolean isAutoCloseConnection) {
        this.dao = dao;
        this.connection = connection;
        this.isAutoCloseConnection = isAutoCloseConnection;
    }

    public BaseService(AbstractDao<T> dao) {
        this(dao, null, true);
    }

    public BaseService(AbstractDao<T> dao, Connection connection) {
        this(dao, connection, true);
    }
    
    public BaseService(AbstractDao<T> dao, boolean isAutoCloseConnection) {
        this(dao, null, isAutoCloseConnection);
    }
    
    @Override
    public int create(T obj) {
        int insertedId = -1;

        try {
            dao.setConnection(getConnection());
            insertedId = dao.create(obj);
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            try {
                closeConnection();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }

        return insertedId;
    }

    @Override
    public void delete(int id) {
        try {
            dao.setConnection(getConnection());
            dao.delete(id);
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            try {
                closeConnection();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }

    @Override
    public void update(T obj) {
        try {
            dao.setConnection(getConnection());
            dao.update(obj);
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            try {
                closeConnection();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }

    public void setDao(AbstractDao<T> dao) {
        this.dao = dao;
    }

    public boolean isAutoCloseConnection() {
        return isAutoCloseConnection;
    }

    public void setAutoCloseConnection(boolean isAutoCloseConnection) {
        this.isAutoCloseConnection = isAutoCloseConnection;
    }

    /**
     * Get the connection. If this.connection is null or was cloased, 
     * then it returns new connection from connection pull. 
     * @return connection with database
     * @throws SQLException
     */
    protected Connection getConnection() throws SQLException {
        if (connection != null && !connection.isClosed()) 
            return connection;
        else return connection = ConnectionManager.getInstance().getConnection();
    }

    /**
     * Close this.connection. It should be called if you finish work with logical session with database.
     * If field isAutoCloseConnection is true, this method would close connection, else - not
     * @throws SQLException
     */
    protected void closeConnection() throws SQLException {
        if (connection == null) return;
        if (!isAutoCloseConnection) return;
        connection.close();
    }
}
